package tech.tongyu.bct.omssdk.service.impl;

import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.tongyu.bct.market.dto.SwapInstrumentWhiteListDTO;
import tech.tongyu.bct.market.dto.swapWhite.SwapInstrumentWhitelistCriteria;
import tech.tongyu.bct.market.feign.SwapInstrumentWhiteListExternalClient;
import tech.tongyu.bct.omssdk.service.IsolationWallService;
import tech.tongyu.idp.api.OmsRiskControlRuleService;
import tech.tongyu.idp.api.OmsSecurityPoolService;
import tech.tongyu.idp.model.*;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class IsolationWallServiceImpl implements IsolationWallService {
    @Autowired
    private SwapInstrumentWhiteListExternalClient swapInstrumentWhiteListExternalClient;

    @Autowired
    private OmsSecurityPoolService omsSecurityPoolService;

    @Autowired
    private OmsRiskControlRuleService omsRiskControlRuleService;

    Gson gson = new Gson();

    public static final String POOL_NAME_BUY = "禁止交易_全局_买";
    public static final String POOL_NAME_SELL = "禁止交易_全局_卖";

    /**
     * 获取隔离墙标的信息
     *
     * @return
     */
    @Override
    public List<SwapInstrumentWhiteListDTO> getSwapInstrumentWhiteList() {
        // 构建查询条件，包含所有可能的标签
        SwapInstrumentWhitelistCriteria criteria = SwapInstrumentWhitelistCriteria.builder()
                .labels(Arrays.asList("DMA", "SEPAR"))
                .build();
        // 调用 list 方法获取所有符合初步条件的标的
        List<SwapInstrumentWhiteListDTO> allEntries = swapInstrumentWhiteListExternalClient.list(criteria);
        log.info("初步过滤后的标的数量：{}", allEntries.size());
        //todo 总结一下有哪些json转entity entity转json的工具类，目的只要能想得起来，使用这些工具。JSON转Bean Bean转JSON，JSON转Map Map转JSON等等等
        log.info("初步过滤后的标的：{}", gson.toJson(allEntries));
        // 进行二次过滤，确保符合所有需求的条件
        //todo Stream流的使用，几个方法搞懂即可，filter、map（最终集合的值）
        List<SwapInstrumentWhiteListDTO> filteredEntries = allEntries.stream()
                .filter(entry -> {
                    List<String> labels = entry.getWhiteListLabels(); // 获取标的的标签列表
                    return  labels.contains("DMA") && !labels.contains("BCT") &&// 必须包含 DMA 标签
                            !labels.contains("FORBID") && labels.contains("SEPAR"); // 并且包含 FORBID 或 SEPAR 中的一个
                })
                .collect(Collectors.toList());
        log.info("过滤后的标的数量：{}", filteredEntries.size());
        if(filteredEntries.isEmpty()) return null;
        return filteredEntries;
    }


    /**
     * 查询禁止交易池，并更新禁止交易池的标的信息
     *
     * @param bdList
     */
    @Override
    public List<OmsSecurityPool> completeSecurityPool(List<SwapInstrumentWhiteListDTO> bdList, OmsSystem omsSystem, List<String> poolNames) {
        if(bdList == null) return null;
        // 定义需要处理的禁止交易池名称
        Map<String, OmsSecurityPool> poolMap = new HashMap<>();

        // 查询所有禁止交易池，并存入Map中
        List<OmsSecurityPool> omsSecurityPools = omsSecurityPoolService.fetchSecurityPool(omsSystem, null);
        for (OmsSecurityPool pool : omsSecurityPools) {
            if (poolNames.contains(pool.getName())) {
                poolMap.put(pool.getName(), pool);
            }
        }

        // 动态创建不存在的禁止交易池
        for (String poolName : poolNames) {
            poolMap.putIfAbsent(poolName, createSecurityPool(poolName));
        }

        // 检查bdList是否为空
        if (bdList == null || bdList.isEmpty()) {
            log.info("bdList is empty. No updates will be made to the security pools.");
        } else {
            // 更新标的内容
            for (String poolName : poolNames) {
                OmsSecurityPool pool = poolMap.get(poolName);
                Map<String, SecurityPoolDetail> detailMap = new HashMap<>();

                // 现有的SecurityPoolDetail对象去重
                for (SecurityPoolDetail existingDetail : pool.getSecurityPoolDetailList()) {
                    String key = existingDetail.getSecurityExchange() + "|" + existingDetail.getTradeSymbol();
                    detailMap.put(key, existingDetail);
                }


                for (SwapInstrumentWhiteListDTO bd : bdList) {
                    String exchange = StrUtil.subAfter(bd.getInstrumentId(), ".", true);
                    String symbol = StrUtil.subBefore(bd.getInstrumentId(), ".", true);

                    // 生成唯一的键
                    String key = exchange + "|" + symbol;

                    // 如果map中没有这个键，说明是新的条目
                    if (!detailMap.containsKey(key)) {
                        SecurityPoolDetail detail = new SecurityPoolDetail();
                        detail.setSecurityExchange(SecurityExchange.valueOf(exchange));
                        detail.setTradeSymbol(symbol);
                        detailMap.put(key, detail);
                    }

                }

                // 更新池中的SecurityPoolDetail列表
                pool.setSecurityPoolDetailList(new ArrayList<>(detailMap.values()));
                omsSecurityPoolService.saveSecurityPool(omsSystem, pool);
            }
            log.info("更新后的禁止交易池数量：{}", poolMap.size());
        }

        poolMap.values().forEach(pool -> log.info("更新后的禁止交易池：{}", gson.toJson(pool)));
        ArrayList<OmsSecurityPool> res = new ArrayList<>(poolMap.values());
        log.info("更新后的禁止交易池数量：{}", res.size());
        return res;
    }





    @Override
    public void completeRiskControlRule(List<OmsSecurityPool> omsSecurityPoolList) {
        if(omsSecurityPoolList == null) return;
        log.info("禁止交易池列表：{}", gson.toJson(omsSecurityPoolList));
        OmsSecurityPool buySecurityPool = new OmsSecurityPool();
        OmsSecurityPool sellSecurityPool = new OmsSecurityPool();
        for (OmsSecurityPool securityPool : omsSecurityPoolList) {
            if(securityPool.getName().equals(POOL_NAME_BUY)){
                buySecurityPool = securityPool;
            }
            if (securityPool.getName().equals(POOL_NAME_SELL)){
                sellSecurityPool = securityPool;
            }
        }
        // 查询风控规则列表
        List<OmsRiskControlRule> omsRiskControlRules = omsRiskControlRuleService.fetchRiskControlRule(OmsSystem.OMS_SH_1, null);
        log.info("风控规则列表：{}", gson.toJson(omsRiskControlRules));
        OmsRiskControlRule buyRule = findOrInitRule(omsRiskControlRules, Side.Buy, buySecurityPool);
        OmsRiskControlRule sellRule = findOrInitRule(omsRiskControlRules, Side.Sell, sellSecurityPool);
        log.info("买风控规则：{}", gson.toJson(buyRule));
        log.info("卖风控规则：{}", gson.toJson(sellRule));
        try {
            OmsRiskControlRule omsRiskControlRuleBuy = omsRiskControlRuleService.saveRiskControlRule(OmsSystem.OMS_SH_1, buyRule);
            log.info("更新买风控规则成功:{}", gson.toJson(omsRiskControlRuleBuy));
            omsRiskControlRuleService.saveRiskControlRule(OmsSystem.OMS_SH_1, sellRule);
            log.info("更新卖风控规则成功:{}", gson.toJson(sellRule));
            log.info("更新风控规则成功");
        } catch (Exception e) {
            // 异常处理逻辑
            log.error("Failed to save risk control rules", e);
        }
    }


    /**
     * 通过禁止池和方向参数，在风控规则列表里面查找对应规则，如果找到则更新，否则创建新规则。
     * @param rules
     * @param side
     * @param securityPool
     * @return
     */
    private OmsRiskControlRule findOrInitRule(List<OmsRiskControlRule> rules, Side side, OmsSecurityPool securityPool) {
        return rules.stream()
                .filter(rule -> rule != null)
                .filter(rule -> RiskControlType.Prohibition.equals(rule.getRiskControlType()))
                .filter(rule -> RiskControlScope.Global.equals(rule.getClientScope()))
                .filter(rule -> SecurityScopeType.SecurityPool.equals(rule.getSecurityScopeType()))
                .filter(rule -> side.getValue().equals(rule.getSide().getValue()))
                .findFirst()
                .map(rule -> {
                    updateRule(rule, securityPool);
                    return rule;
                })
                .orElseGet(() -> {
                    OmsRiskControlRule newRule = new OmsRiskControlRule();
                    newRule.setRiskControlType(RiskControlType.Prohibition);
                    newRule.setClientScope(RiskControlScope.Global);
                    newRule.setSecurityScopeType(SecurityScopeType.SecurityPool);
                    newRule.setSide(side);
                    updateRule(newRule, securityPool);
                    return newRule;
                });
    }

    /**
     * 更新风控规则
     * @param rule
     * @param securityPool
     */
    private void updateRule(OmsRiskControlRule rule, OmsSecurityPool securityPool) {
        rule.setSecurityPoolList(Arrays.asList(securityPool));
        List<Long> ids = securityPool.getSecurityPoolDetailList().stream()
                .map(SecurityPoolDetail::getSecurityPoolId)
                .collect(Collectors.toList());
        rule.setEffectiveFromText("00:00:00");
        rule.setEffectiveFromMillis(-28800000);
        rule.setEffectiveToText("23:59:59");
        rule.setEffectiveToMillis(86399000);

        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        rule.setStartDate(today.format(formatter));
        rule.setEndDate(today.format(formatter));
        rule.setSecurityPoolIdList(ids);
    }



    private OmsSecurityPool createSecurityPool(String poolName) {
        OmsSecurityPool pool = new OmsSecurityPool();
        pool.setName(poolName);
        pool.setRemove(false);
        pool.setSecurityPoolDetailList(new ArrayList<>());
        return pool;
    }


}
